home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 6
/
QRZ Ham Radio Callsign Database - Volume 6.iso
/
mac
/
files
/
amiga
/
csrc720j.lzh
/
mbtnc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-23
|
17KB
|
806 lines
/*
* MBTNC.C - 12/20/92 - Deal with the tnc.
*/
#include "mb.h"
#ifdef MCH_AMIGA
extern PORTS *devtnc; /* Set by inittnc() in amiga.c */
extern char conn_direction;
char *tcmds[] =
#else
static char *tcmds[] =
#endif
{
"cono on\n",
"cono of\n",
"m on\n",
"m of\n"
};
#ifdef MCH_AMIGA
extern char tmpstr[];
extern short debug;
extern unsigned char vhfstream,hfstream;
word save_mode;
/* FIX 12
The KAM does not just say "*** DISCO" if you send a disco command and
it is already disconnected. No! That would be too easy. It says:
'Can't DISCONNECT, A/V Link state is: DISCONNECTED'
This can tie distnc() up in loop.
So look for this as well.
*/
isother(cp)
char *cp;
{
if(search(cp,"Can't DISCO",11))return true;
return false;
}
#endif
isdis(cp)
char *cp;
{
if (search(cp, "*** DISC", 8)) return true;
return false;
}
isreq(cp)
char *cp;
{
if (matchn(cp, "*** conn", 8)) return true;
if (matchn(cp, "*** Conn", 8)) return true;
return false;
}
islink(cp)
char *cp;
{
return matchn(cp, "*** LINK", 8);
}
iscon(cp)
char *cp;
{
return search(cp, "*** CONN", 8);
}
isretry(cp)
char *cp;
{
if (matchn(cp, "*** Retry count exceeded", 24)) return true;
if (matchn(cp, "*** retry count exceeded", 24)) return true;
return false;
}
alloff()
{
#ifdef MCH_AMIGA
PORTS *p;
if(devtnc->dev == p_serial) {
if(port->mode & ops) {
p = port;
ioport(devtnc);
outstr("ATS0=0\n");
waitcmd(2);
ioport(p);
}
return;
}
#endif
allcmd(t_coff); /* Turn off connects */
allcmd(t_moff); /* Turn off monitoring */
}
allon()
{
#ifdef MCH_AMIGA
PORTS *p;
if(devtnc->dev == p_serial) {
if(port->mode & ops) {
p = port;
ioport(devtnc);
outstr("ATS0=2\n");
waitcmd(2);
ioport(p);
}
return;
}
#endif
allcmd(t_mon); /* Turn on monitoring */
allcmd(t_con); /* Turn on connects */
}
login()
{
register PORTS *p;
register char *i;
readmsg();
readusr();
p = port;
p->lport = cport;
cport->lport = p;
p->errors = 0;
p->msg = NULL;
p->cmdcnt = 0;
p->flags clrbit p_opreq;
p->ec = p->ecuser;
/*
* Prepare to check if this user can indeed connect.
*/
switch (p->dev)
{
case p_console:
p->mode = local;
alloff();
rduser(p->user->call, p->user);
unbl(p->line, p->user->call, ln_call);
log('C', 'S', ' ', p->line);
break;
case p_tnc:
p->mode = remote;
tncstate(); /* Pick up the "... connected to ..." line */
#ifdef MCH_AMIGA
/* FIX 8 */
/* Was this a valid connect? If the BBS saw "*** CONN" but the TNC
is disconnected (both hf and vhf), then it was monitoring someone's
data and it is not a valid connection, so log a bad one and get
out. Need to do same thing when connected to a user who is stupid
enough to send data that looks like a disconnect.
*/
if(p->mode == discon) {
/* force the mode to idle ... the user was never there.
discon means user was there and then disconnected
*/
p->mode = idle;
/* type 'E' log is for errors .... prtlog ignores them */
/* EF is for the false connected message */
log('E','F',' ',p->line);
return;
}
#endif
alloff();
if (p->tmode) trantnc(); else convtnc();
/*
* Remove the "; 1 unacked" that pk-232 puts on status line.
*/
if ((i = strchr(p->line, ';')) isnt NULL) *i = '\0';
if ((i = strchr(p->line, '*')) isnt NULL) *i = '\0';
strcpy(p->line, p->line + 28);
logina(false);
log('C', p->id, ' ', p->line);
break;
#ifdef MCH_AMIGA
case p_nulmdm:
#endif
case p_serial:
p->mode = remote;
p->flags setbit p_trans;
alloff();
strcpy(p->line, p->line + 17);
logina(false);
log('C', p->id, ' ', p->line);
break;
default: ;
}
}
/*
* The login checking process.
*/
logina(link)
short link;
{
register char *p, *q;
register int ssid;
register short nd;
char bullfile[11];
remnl(port->line);
/*
* Clear any pending connect request.
*/
port->flags clrbit p_req;
/*
* Get the users call and ssid.
*/
parse();
ssid = pcall(tcall, port->fld[0]);
/*
* Add the call to J list for port, and for connect.
*/
addcall(port->fld[0], cport);
addcall(port->fld[0], port);
/*
* Save call of connected gateway, if user linked here.
*/
if (link) strncpy(tmp->scr, port->user->call, ln_call);
/*
* Get (or make) this users user record.
*/
rduser(tcall, port->user);
/*
* Update the data in the user record.
*/
port->user->ssid = ssid;
if (link) port->user->port = 'L'; else port->user->port = port->id;
/*
* Get path. Count how many digi in path.
* First, fix digi path in case is a PK-232.
*/
nd = 3;
while (port->flds > 3)
{
strcat(port->fld[2], port->fld[nd]);
port->flds--;
nd++;
}
nd = 0;
if (link) unbl(port->user->path, tmp->scr, ln_call);
else if (port->flds > 2)
{
nd++;
p = port->user->path;
for (q = port->fld[2]; *q; q++)
if (*q isnt ' ') if ((*p++ = *q) is ',') nd++;
*p = '\0';
}
else *port->user->path = '\0';
/*
* If this user is excluded, exclude him.
*/
if (port->user->options & u_exclude) { port->mode = exclude; return; }
/*
* At last, decide if this user CAN connect.
* If sysop or bbs, can always connect.
*/
if (port->user->options & (u_sysop | u_bbs)) {
#ifdef MCH_AMIGA
conn_direction = '<';
user_title(port->user->call);
#endif
outstr(vers);
return;
}
/*
* If this turkey has illegal call, kick him right off.
*/
if (port->priv & p_ilcal) if (!iscall(tcall)) { port->mode = exclude; return; }
/*
* This user isn't a bbs. If port is bbs only, bye bye.
*/
if (port->priv & p_bbs) { port->mode = exclude; return; }
/*
* If user connected through too many digi, bye bye.
*/
if (nd > port->ndigi) { port->mode = exclude; return; }
/*
* Well, this user can indeed connect on this port.
* Send our "I am a machine message"
*/
outstr(vers);
#ifdef MCH_AMIGA
/* Put the call in the title bar */
conn_direction = '<';
user_title(port->user->call);
#endif
sprintf(bullfile, "BULLETIN.%c",port->id);
if ((port->fl = fopen(bullfile, "r")) isnt NULL)
{
while( fgets(tmp->scr, scrmax, port->fl) isnt NULL)
{
if (chkdis()) break;
prtx(tmp->scr);
}
fclose(port->fl);
}
/*
* If not an expert user, give login message and
* tell about unread messages.
*/
if (!(port->user->options & u_expert))
prtm(motd);
newmsg();
}
/*
* Execute a command to each port:
* Connects ok, monitor on, etc.
*/
allcmd(index)
int index;
{
register PORTS *p, *was;
byte ec;
was = port;
for (p = porthd; p isnt NULL; p = p->next)
{
ioport(p);
if(p->dev is p_tnc)
{
p->flags clrbit p_give;
ec = p->ec;
p->ec = p->eccmds;
outstr(tcmds[index]);
waitcmd(0);
p->flags setbit p_give;
p->ec = ec;
}
}
ioport(was);
}
alltnc(cp)
char *cp;
{
register PORTS *p, *was;
byte ec;
was = port;
for (p = porthd; p isnt NULL; p = p->next) switch(p->dev)
{
case p_tnc:
ioport(p);
ec = p->ec;
p->ec = p->eccmds;
p->flags clrbit p_give;
outstr(cp);
waitcmd(0);
p->flags setbit p_give;
p->ec = ec;
break;
default: ;
}
ioport(was);
}
/*
* Execute a command to the current port:
* Connects ok, monitor on, etc.
*/
onecmd(index)
int index;
{
register byte ec;
if(port->dev is p_tnc)
{
ec = port->ec;
port->ec = port->eccmds;
port->flags clrbit p_give;
outstr(tcmds[index]);
waitcmd(0);
port->ec = ec;
port->flags setbit p_give;
}
}
onetnc(cp)
char *cp;
{
register byte ec;
if (port->dev is p_tnc)
{
ec = port->ec;
port->ec = port->eccmds;
port->flags clrbit p_give;
outstr(cp);
waitcmd(0);
port->ec = ec;
port->flags setbit p_give;
}
}
/*
* Need to distinguish between "disconect in progress", "disconnected",
* "connected", "connect in progress".
*/
issta(cp)
char *cp;
{
register char *p;
p = cp;
#ifndef MCH_AMIGA
if (matchn(cp, "cmd:", 4)) p += 4;
#else
/* There could be more than one cmd: lurking on the line */
while (matchn(cp, "cmd:", 4)) strcpy(p,p+4);
/*PH Check for beginning of line from a KAM
of the form 'A/V' or 'A/H' */
if(p[1] == '/') {
strcpy(p,p+4);
}
#endif
if (!matchn(p, "Link sta", 8)) return false;
if (matchn(p + 15, "DISC", 4) and (strlen(p) < 30)) port->mode = discon;
return true;
}
/*
* Put tnc in converse mode.
*/
convtnc()
{
register byte ec;
if(port->dev is p_tnc)
{
ec = port->ec;
port->ec = port->eccmds;
outstr("conv\n");
port->ec = ec;
wait(2);
}
}
trantnc()
{
register byte ec;
if(port->dev is p_tnc)
{
ec = port->ec;
port->ec = port->eccmds;
outstr("trans\n");
port->flags setbit p_trans;
port->ec = ec;
wait(1);
}
}
/*
* Put tnc in command mode.
*/
cmdtnc()
{
register byte ec;
if(port->dev is p_tnc)
{
ec = port->ec;
port->ec = port->eccmds;
port->flags clrbit p_give;
if (port->flags & p_trans) breakport(); else outchar(ctl_c);
waitcmd(1);
port->ec = ec;
port->flags setbit p_give;
port->flags clrbit p_trans;
}
}
/*
* Discover the state of the device on the current port.
*/
tncstate()
{
register byte ec;
if(port->mode & idle) return;
if(port->dev is p_tnc) {
ec = port->ec;
port->ec = port->eccmds;
cmdtnc();
port->flags clrbit p_give;
#ifdef MCH_AMIGA
/* If this is the amiga version but it doesn't look like a
KAM then just use the usual code
*/
if(!hfstream) {
#endif
outstr("C\n");
while(true) {
getdat();
if(issta(port->line)) {
waitcmd(1);
port->ec = ec;
port->flags setbit p_give;
return;
}
else {
cmdtnc();
port->flags clrbit p_give;
outstr("C\n");
}
}
#ifdef MCH_AMIGA
}
while(true) {
/* Try to get an HF status report. */
/* Ask for HF status first. The reason is that if both streams
are disconnected, then this procedure will leave the TNC on
the VHF stream during idle periods. So if you use the TAlk
command to talk to the TNC and just give it a Connect command
it will by default send it out the VHF port.
*/
Delay(10L);
outchar(hfstream);
outstr("AC\n");
getdat();
/* save the port mode before calling issta. If the HF port is
DISConnected it will force the mode to discon. This must be
restored to its original value as it was after the getdat
when the VHF port is tried because otherwise distnc() and
other routines will think the VHF side is disconnected even
if it is not, and they will not force a disconnect when one
is needed.
Also, saving the mode here immediately AFTER the first getdat
will preserve the 'forced' state if the SYSOP had used the
^F to force the port to disconnect because we call getdat
again and the second call won't know the ^F has happened.
*/
save_mode = port->mode;
if(issta(port->line)) {
/* It's a valid status line */
waitcmd(1);
/* If it returns not disconnected then it's the HF channel */
if(port->mode != discon) {
port->ec = ec;
port->flags setbit p_give;
return;
}
/* The HF channel is not connected so either the VHF port
is disconnected, in which case return OR it is connected
or connecting in which case we still return but force the
TNC onto the VHF channel
*/
outchar(vhfstream);
outstr("AC\n");
/* now restore the port mode again - getdat will only override
the existing mode if something goes wrong so if the last
mode was forced, it will remain forced unless, for example,
it now sees a *** DISC.
*/
port->mode = save_mode;
getdat();
if(issta(port->line)) {
waitcmd(1);
port->ec = ec;
port->flags setbit p_give;
return;
}
}
/* If can't get a valid status line from either then fire another
control C at the port and try again
*/
cmdtnc();
port->flags clrbit p_give;
}
#endif
}
}
/*
* Disconnect tnc.
*/
#ifdef MCH_AMIGA
/* This is the last remaining busy-wait routine in cbbs. If it can be
removed then the settmr and chktmr routines can also be removed from
funcs.c
*/
#endif
distnc()
{
register int tsave;
register short done;
byte ec;
tncstate();
if(port->mode & idle) return;
ec = port->ec;
port->ec = port->eccmds;
switch(port->dev) {
#ifdef MCH_AMIGA
case p_nulmdm:
#endif
case p_serial:
if(!(port->mode & discon)) outstr("*** DISCONNECTED\n");
break;
case p_tnc:
if (port->mode & discon) break;
port->flags clrbit p_give;
outstr("D\n"); /* This does not eat cmd:, thus dtime not used */
settmr(&port->expire, port->dtime);
while(true) {
if(instat()) {
tsave = port->ctime;
port->ctime = port->dtime;
getdat();
port->ctime = tsave;
#ifndef MCH_AMIGA
if(isdis(port->line))
#else
/* FIX 12 */
if(isdis(port->line) || isother(port->line))
#endif
{
waitcmd(1);
port->ec = ec;
port->flags setbit p_give;
return;
}
}
if(!chktmr(port->expire)) {
outstr("D\n");
#ifndef MCH_AMIGA
while(!isdis(port->line)) getdat();
#else
/* FIX 12 */
while(!isdis(port->line) && !isother(port->line)) getdat();
#endif
waitcmd(1);
port->ec = ec;
port->flags setbit p_give;
return;
}
}
break;
}
port->ec = ec;
port->mode = discon;
}
/*
* Send connect string to tnc.
*/
contnc(p)
char *p;
{
register byte ec;
#ifdef MCH_AMIGA
register char *q;
#endif
ec = port->ec;
port->ec = true;
switch (port->dev)
{
case p_tnc:
outstr(p);
port->ec = port->eccmds;
#ifndef MCH_AMIGA
/*
DON'T DO THIS. MFJ (and some other TNCs) which, for proper BBS operation,
should have BBSMSGS ON and NEWMODE ON, does NOT send a cmd: prompt after
a Connect command. With any other combination of BBSMSGS and NEWMODE, the
stupid thing sends cmd: but the one combination that we need to work,
doesn't!
So the waitcmd(0) here will not see a cmd: prompt but it will see, AND
THROW AWAY, the *** CONNECTED message. This means that the loop which
will try ot find the CONNECTED message will fail.
*/
waitcmd(0);
#endif
break;
case p_serial:
#ifdef MCH_AMIGA
outstr(p);
while(1) {
getdat();
q = port->line;
/* Ignore the error returns from getdat on a serial line. It looks
for carrier and dies if it isn't there. But we know it can't be
there yet.
*/
if(*q == 0)continue;
if((*q == '\n') || (*q == '\r'))continue;
if((*q == 'A') && (*(q+1) == 'T'))continue;
if(matchn(q,"RING",4))continue;
if(matchn(q,"CONNECT",7))break;
port->mode = idle;
printf("PORT IDLE\n");
return;
}
/* The other end, notably the ZyXEL, may not have seen its CONNECT
message yet ... so we must Delay here before sending the connect
*/
Delay(250L);
port->mode = remote;
#endif
#ifdef MCH_AMIGA
case p_nulmdm:
/* The initial \n will flush any garbage generated in the modem during
the connect procedure.
*/
prtx("\n*** CONNECTED to $O\n");
#else
prtx("*** CONNECTED to $O\n");
#endif
}
port->ec = ec;
}
/*
* Wait for "cmd:" prompt.
*/
#ifndef MCH_AMIGA
waitcmd(x)
int x;
{
static char *wanted = "cmd:";
register short i;
long l;
int t;
if (s_flag & s_dv) t = 5; else t = 2;
if (x) t = x;
if(port->dev is p_tnc)
{
settmr(&l, t);
for (i = 0; i < 4;)
{
if (instat()) if (inchar() is *(wanted + i)) i++; else i = 0;
if (!chktmr(l))
{
if (!(port->eccmds))
bdos(2,tolower(port->id),0); return;
}
}
if (!(port->eccmds)) bdos(2,port->id,0);
}
}
#endif